#!/bin/bash

# password previously encrypted:
# openssl enc -aes-256-cbc -iter 99999 -a -pass file:/etc/machine-id -out "$passfile"

sep="################################################"
server="posteo.de"
user=danter
me="${0##*/}"
tag=Zaphod
passfile="$HOME/.local/share/$me.txt"

countonly=0
debug=0
after=''

while getopts "cda:" opt; do
  case $opt in
    c)
      countonly=1
      ;;
    d)
      debug=1
      ;;
    a)
      after="$OPTARG"
      ;;
  esac
done

debug() {
    [[ "$debug" != 1 ]] && return
    (($# > 1)) && printf "$@" || echo "$1"
}
remCR() {
    # removes carriage returns from output
    # works directly on $out
    out="${out//$'\r'/}"
}
mimedecode() {
    # only if Perl & its Encode module are available
    # https://superuser.com/a/972248
    x="$(perl -CS -MEncode -e "print decode('MIME-Header', '$out')" 2>/dev/null)"
    [ -n "$x" ] && out="$x" || out="$@"
}
# Start the session
coproc SSL { openssl s_client -connect "$server":993 -crlf -quiet 2>/dev/null; } || exit 1

# Make sure openssl is dead when exiting
trap 'kill $SSL_PID 2>/dev/null' EXIT

# LOGIN
line="$tag login $user@$server"
echo "$line $(openssl enc -aes-256-cbc -iter 99999 -a -pass file:/etc/machine-id -d -in "$passfile")" >&${SSL[1]}
debug "$line super_secret_password"

# Catch output loop. Remove the printf if you want it quiet
while read -r out; do
    debug '%q\n' "$out"
    # This reply tells us the server is done and waiting for more input
    [[ "$out" == "$tag "* ]] && break
done <&${SSL[0]}
debug "$sep"

# Now we're talking to the server
echo "$tag lsub INBOX \"*\"" >&${SSL[1]}
debug "$tag lsub INBOX \"*\""

# Catch output loop. Remove the printf if you want it quiet
subs=(); count=0
while read -r out; do
    debug '%q\n' "$out"
    # This is the first stepof the info we're after
    [[ "$out" == '* LSUB '* ]] && {
        out="${out#*\".\" }"
        remCR # remove carriage return!
        subs[count++]="$out"
        continue
    }
    # Again, this reply tells us the server is done and waiting for more input
    [[ "$out" == "$tag "* ]] && break
done <&${SSL[0]}
debug "$sep"

# Now we're talking to the server
declare -A unseen=()
for i in "${subs[@]}"; do

    # 1. select folder
    echo "$tag select $i" >&${SSL[1]}
    debug "$tag select $i"

    # Catch output loop.
    found=0
    while read -r out; do
        debug '%q\n' "$out"
        # no need to search _each_ folder for unseen messages!
        [[ "$out" == '* OK [UNSEEN '* ]] && found=1
        [[ "$out" == "$tag "* ]] && break
    done <&${SSL[0]}

    # 2. search for unseen mail
    if [[ "$found" == 1 ]]; then
        echo "$tag search (unseen)" >&${SSL[1]}
        debug "$tag search (unseen)"
    
        # Catch output loop.
        while read -r out; do
            debug '%q\n' "$out"
            # 3. if SEARCH is followed by a space there are unseen messages
            [[ "$out" == '* SEARCH '* ]] && {
                out="${out#*SEARCH }"
                remCR
                # 4. asssign to array
                unseen[$i]="$out"
                continue
            }
            [[ "$out" == "$tag "* ]] && break
        done <&${SSL[0]}
    fi
done
debug "$sep"

final=""
# now also get subject lines
for folder in "${!unseen[@]}"; do
    # select folder
    echo "$tag select $folder" >&${SSL[1]}
    debug "$tag select $folder"
    while read -r out; do
        debug '%q\n' "$out"
        # This reply tells us the server is done and waiting for more input
        [[ "$out" == "$tag "* ]] && break
    done <&${SSL[0]}
    # make array from numerical mail ids
    arr=(${unseen[$folder]})
    # removes leading & trailing quotes from folder name, for final display only
    folder="${folder#\"}";folder="${folder#\'}";folder="${folder%\"}";folder="${folder%\'}"
    final="${final}\n$folder"
    if [[ "$countonly" == 1 ]]; then
        final="$final: ${#arr[@]} unread mail"
        (( ${#arr[@]} > 1 )) && final="${final}s" || final="$final"
    else
        for i in "${arr[@]}"; do
            echo "$tag fetch $i body.peek[header.fields (subject)]" >&${SSL[1]}
            debug "$tag fetch $i body.peek[header.fields (subject)]"
            # Catch output loop.
            while read -r out; do
                debug '%q\n' "$out"
                [[ "$out" == "Subject: "* ]] && {
                    out="${out#Subject: }"
                    remCR
                    [[ "${out,,}" == '=?utf-8?'*'?=' ]] && mimedecode
                    final="$final\n - $out"
                    continue
                }
                [[ "$out" == "$tag "* ]] && break
            done <&${SSL[0]}
        done
    fi
done
final="${final#\\n}"
final="${final%\\n}"

# That's all we wanted. Logging out
echo "$tag logout" >&${SSL[1]}
debug "$tag logout"
while read -r out; do
    debug '%q\n' "$out"
    [[ "$out" == "$tag "* ]] && break
done <&${SSL[0]}
# at this point the openssl coproc should quit.
debug "$sep"

if [[ "$final" != "" ]]; then
    [[ "$after" != "" ]] && final="$final$after"
    echo -e "$final"
fi
